﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System.Diagnostics;


namespace Tank
{
    class Input
    {
        private static volatile Input instance;
        private static object syncRoot = new Object();
        private KeyboardState oldState, newState;
        private Dictionary<PlayerIndex, GamePadState> gamePad = new Dictionary<PlayerIndex, GamePadState>();
        private Dictionary<PlayerIndex, GamePadState> oldGamePad = new Dictionary<PlayerIndex, GamePadState>();
        private PlayerIndex currPlayer;
        private bool usingGamePad = false;
        private bool usingKeyboard = true;

        private Input()
        {
            if (IsControllerConnected())
            {
                usingGamePad = true;
                usingKeyboard = false;
            }
            
            UpdateGamePads();
        }

        public static Input Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                            instance = new Input();
                    }
                }
                return instance;
            }
        }

        public void Update()
        {
            if(usingKeyboard)
                UpdateKeyboard();
            else
                UpdateGamePads();
        }

        //=============================================================
        // KEYBOARD INTERACTIONS
        //=============================================================
        private void UpdateKeyboard()
        {
            oldState = newState;
            newState = Keyboard.GetState();
        }

        public bool IsKeyDown(Keys key)
        {
            return(newState.IsKeyDown(key));
        }

        public bool IsKeyUp(Keys key)
        {
            return (newState.IsKeyUp(key));
        }

        public bool DidKeyJustGoDown(Keys key)
        {
            
            if (oldState.IsKeyUp(key) && newState.IsKeyDown(key))
                return true;

            return false;
        }

        public bool DidKeyJustGoUp(Keys key)
        {
            if (oldState.IsKeyDown(key) && newState.IsKeyUp(key))
                return true;

            return false;
        }
        //----------End Keyboard Interactions----------//

        //=============================================================
        // GAMEPAD INTERACTIONS
        //=============================================================
        private void UpdateGamePads()
        {
            for( int i = 0; i < 4; ++i)
            {
                if (gamePad.Count > i)
                {
                    oldGamePad[(PlayerIndex)i] = gamePad[(PlayerIndex)i];
                }
                gamePad[(PlayerIndex)i] = GamePad.GetState((PlayerIndex)i);
            }
            
        }

        public bool IsControllerConnected()
        {
            for (int i = 0; i < 4; ++i)
            {
                if (GamePad.GetState((PlayerIndex)i).IsConnected)
                {
                    return true;
                }
            }
            return false;
        }

        // Returns a bool array representing if a controller is connected or not. 0 = PlayerIndex.One, 1 = PlayerIndex.Two, etc
        public List<PlayerIndex> GetConnectedControllers()
        {
            List<PlayerIndex> connected = new List<PlayerIndex>();
            for (int i = 0; i < 4; ++i)
            {
                if (GamePad.GetState((PlayerIndex)i).IsConnected)
                {
                    connected.Add((PlayerIndex)i);
                }
            }
            return connected;
        }

        public void AddPlayer(PlayerIndex player)
        {
            gamePad.Add(player, new GamePadState());
            usingGamePad = true;
            usingKeyboard = false;
            currPlayer = player;
        }

        public bool IsButtonDown(Buttons button, PlayerIndex player)
        {
            if (gamePad[player].IsButtonDown(button))
            {
                return true;
            }
            return false;
        }

        public bool IsButtonUp(Buttons button, PlayerIndex player)
        {
            if (gamePad[player].IsButtonUp(button))
            {
                return true;
            }
            return false;
        }

        public Vector2 GetLeftThumbStick(PlayerIndex player)
        {
            return gamePad[player].ThumbSticks.Left;
        }

        public Vector2 GetRightThumbStick(PlayerIndex player)
        {
            return gamePad[player].ThumbSticks.Right;
        }

        public bool DidButtonJustGoDown(Buttons button, PlayerIndex player)
        {
            if(oldGamePad[player].IsButtonUp(button) && gamePad[player].IsButtonDown(button))
            {
                return true;
            }
            return false;
        }

        public bool IsLeftTriggerDown(Buttons button, PlayerIndex player)
        {
            float triggerPoint = 0.8f;
            GamePadTriggers newTriggers = gamePad[player].Triggers;
            if (newTriggers.Left >= triggerPoint)
                return true;
            return false;
        }

        public bool DidTriggerJustGoDown(Buttons button, PlayerIndex player)
        {
            float triggerPoint = 0.8f;
            GamePadTriggers oldTriggers = oldGamePad[player].Triggers;
            GamePadTriggers newTriggers = gamePad[player].Triggers;
            if((oldTriggers.Left < triggerPoint && newTriggers.Left >= triggerPoint) ||
               (oldTriggers.Right < triggerPoint && newTriggers.Right >= triggerPoint))
            {
                return true;
            }
            return false;
        }

        public bool DidRightTriggerJustGoDown(Buttons button, PlayerIndex player)
        {
            float triggerPoint = 0.8f;
            GamePadTriggers oldTriggers = oldGamePad[player].Triggers;
            GamePadTriggers newTriggers = gamePad[player].Triggers;
            if (oldTriggers.Right < triggerPoint && newTriggers.Right >= triggerPoint)
            {
                return true;
            }
            return false;
        }

        public bool DidLeftTriggerJustGoDown(Buttons button, PlayerIndex player)
        {
            float triggerPoint = 0.8f;
            GamePadTriggers oldTriggers = oldGamePad[player].Triggers;
            GamePadTriggers newTriggers = gamePad[player].Triggers;
            if (oldTriggers.Left < triggerPoint && newTriggers.Left >= triggerPoint) 
            {
                return true;
            }
            return false;
        }

		public bool DidLeftTriggerJustGoUp(Buttons button, PlayerIndex player)
		{
			float triggerPoint = 0.8f;
			GamePadTriggers oldTriggers = oldGamePad[player].Triggers;
			GamePadTriggers newTriggers = gamePad[player].Triggers;
			if (oldTriggers.Left >= triggerPoint && newTriggers.Left < triggerPoint)
			{
				return true;
			}
			return false;
		}

        public bool DidButtonJustGoUp(Buttons button, PlayerIndex player)
        {
            if (oldGamePad[player].IsButtonDown(button) && gamePad[player].IsButtonUp(button))
            {
                return true;
            }
            return false;
        }

        public float GetLeftTrigger(PlayerIndex player)
        {
            return gamePad[player].Triggers.Left; 
        }

        public float GetRightTrigger(PlayerIndex player)
        {
            return gamePad[player].Triggers.Right;
        }
        //----------End Gamepad Interactions----------//


        //=============================================================
        // bools to determine which input is going to be used.
        //=============================================================
        public bool UsingGamePad
        {
            get { return usingGamePad; }
        }

        public bool UsingKeyBoard
        {
            get { return usingKeyboard; }
        }
    }
}
